package com.tct.worktimeboard.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tct.worktimeboard.config.DataSourceContextHolder;
import com.tct.worktimeboard.entity.OaDept;
import com.tct.worktimeboard.entity.OaUser;
import com.tct.worktimeboard.entity.UserInfo;
import com.tct.worktimeboard.entity.enums.SexEnum;
import com.tct.worktimeboard.mapper.OaDeptMapper;
import com.tct.worktimeboard.mapper.OaUserMapper;
import com.tct.worktimeboard.service.IUserInfoService;
import com.tct.worktimeboard.service.OAService;
import com.tct.worktimeboard.service.OaDeptService;
import com.tct.worktimeboard.service.OaUserService;
import com.tct.worktimeboard.util.JsonUtil;
import com.tct.worktimeboard.util.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Huhailong
 * @Description
 * @Date 2021/3/26.
 */
@Slf4j
@Service
public class OAServiceImpl implements OAService {

    @Autowired
    OaUserService oaUserService;
    @Autowired
    OaDeptService oaDeptService;
    @Autowired
    IUserInfoService userInfoService;
    @Resource
    OaUserMapper oaUserMapper;
    @Autowired
    RestTemplate restTemplate;
    @Value("${oa.user.url}")
    private String oaUserUrl;
    @Value("${oa.user.host}")
    private String oaUserHost;
    @Value("${oa.dept.url}")
    private String oaDeptUrl;
    @Value("${oa.dept.host}")
    private String oaDeptHost;

    @Override
    public JSONArray getOaUser() {
        return getOaData(oaUserUrl,oaUserHost);
    }

    @Override
    public JSONObject importOaUser() {
        return importDB();
    }

    @Override
    public JSONObject importOaDept() {
        importDeptDB();
        return JsonUtil.toJsonData();
    }

    @Override
    public JSONObject registerBatch(String registerUrl) {
        register(registerUrl);
        return JsonUtil.toJsonData();
    }

    @Override
    public JSONObject refreshDept() {
        List<String> deptNameList = importDeptDB();
        return userInfoService.refreshDept(deptNameList.stream().distinct().collect(Collectors.toList()));
    }

    /**
     * 同步用户
     * @return 返回导入状态
     */
    private JSONObject importDB(){
        OaUser flagUser = oaUserService.importFlag();
        int flagCode = 0;
        if(flagUser!=null){
            flagCode = Integer.parseInt(flagUser.getCode());
            log.info("-------------------上次导入截至到工号为："+flagUser.getCode()+"---------------");
        }
        JSONArray array = getOaUser();
        List<OaUser> userList = new ArrayList<>();
        log.info("-------------------------开始执行入库操作（step1：封装对象）-----------------------");
        for(int i=0; i<array.size(); i++){
            OaUser user = new OaUser();
            JSONObject object = array.getJSONObject(i);
            if(object.get("CODE")!=null&&object.getInteger("ENABLESTATE")!=3&&Integer.parseInt(object.getString("CODE"))>flagCode){  //导入存在工号，去掉状态为已停用的员工
                user.setUserCode(object.getString("USER_CODE"));
                user.setUserName(object.getString("USER_NAME"));
                user.setCode(object.getString("CODE"));
                user.setEnablestate(object.getString("ENABLESTATE"));
                user.setEmail(object.getString("EMAIL"));
                user.setMobile(object.getString("MOBILE"));
                user.setId(object.getString("ID"));
                user.setSex(object.getString("SEX"));
                user.setPkDept(object.getString("PK_DEPT"));
                user.setPkGroup(object.getString("PK_GROUP"));
                user.setPkOrg(object.getString("PK_ORG"));
                user.setImportStatus(false);    //判断是否已注册
                userList.add(user);
            }
        }
        if(userList.isEmpty()){
            log.info("-----------------------未发现新用户------------------");
            return JsonUtil.toJsonData();
        }
        log.info("----------------------------用户对象封装完成（更新用户数: "+userList.size()+"），开始入库--------------------------------");
        oaUserService.saveBatch(userList);
        log.info("-----------------------------人员信息入库成功----------------------------");
        return JsonUtil.toJsonData();
    }

    /**
     * 导入部门
     */
    private List<String> importDeptDB(){
        //刷新部门部门表
        oaDeptService.remove(new QueryWrapper<>());
        JSONArray array = getOaDept();
        List<OaDept> deptList = new ArrayList<>();
        List<String> deptNameList = new ArrayList<>();
        log.info("------------------------------开始执行部门导入--------------------------");
        for(int i=0;  i<array.size(); i++){
            OaDept dept = new OaDept();
            JSONObject object = array.getJSONObject(i);
            dept.setCode(object.getString("CODE"));
            dept.setId(object.getString("PK_DEPT"));
            dept.setName(object.getString("NAME"));
            dept.setPkGroup(object.getString("PK_GROUP"));
            dept.setPkOrg(object.getString("PK_ORG"));
            deptList.add(dept);
            deptNameList.add(object.getString("NAME"));
        }
        log.info("-------------------------------部门列表封装完成，执行入库------------------------");
        oaDeptService.saveBatch(deptList);
        log.info("-------------------------------入库完成---------------------------------");
        return deptNameList;
    }

    /**
     * 通过OA接口获取部门信息
     * @return 返回json数组
     */
    private JSONArray getOaDept(){
        return getOaData(oaDeptUrl,oaDeptHost);
    }

    /**
     * OA接口调用
     * @param url 接口地址
     * @param host header host
     * @return 返回json数组
     */
    private JSONArray getOaData(String url, String host){
        HttpHeaders headers = new HttpHeaders();
        System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
        headers.add(HttpHeaders.HOST,host);
        headers.add(HttpHeaders.CONTENT_TYPE,MediaType.APPLICATION_JSON_VALUE);
        Map<String,String> map = new HashMap<>();
        map.put("query","0");
        HttpEntity<String> request = new HttpEntity<>(JSONObject.toJSONString(map),headers);
        String response = restTemplate.postForObject(url, request, String.class);
        return JSONArray.parseArray(response);
    }

    private void register(String registerUrl) {
        HttpHeaders headers = new HttpHeaders();
        List<Map<String, Object>> registerMap = oaUserService.getRegisterData();
        log.info("将要注册："+registerMap);
        for(Map<String,Object> map : registerMap){
            Map<String,Object> registerData = new HashMap<>();
            registerData.put("username",map.get("userCode"));
            registerData.put("password","1234qwer");
            Map<String,Object> userInfo = new HashMap<>();
            userInfo.put("userNum",map.get("code"));
            userInfo.put("name",map.get("userName"));
            if(map.get("sex") != null){
                userInfo.put("gender", SexEnum.getSexNameFromCode(map.get("sex").toString()));
            }
            userInfo.put("department",map.get("deptName"));
            userInfo.put("phone",map.get("mobile"));
            registerData.put("userInfo",userInfo);
            HttpEntity<String> request = new HttpEntity<>(JSONObject.toJSONString(registerData),headers);
            headers.setContentType(MediaType.APPLICATION_JSON);
            try{
                Thread.sleep(1000); //1秒执行一次
                String response = restTemplate.postForObject(registerUrl, request, String.class);
                oaUserService.update(new UpdateWrapper<OaUser>().eq("user_code",map.get("userCode")).set("import_status",1));
                JSONObject object = JSON.parseObject(response);
                int overNum = oaUserService.count(new QueryWrapper<OaUser>().eq("import_status", 1));
                log.info("当前注册人："+map.get("userName")+" -> 注册结果->"+object.get("status").toString()+" message->"+object.get("message")+" 已注册人数->"+overNum);
            }catch (Exception e){
                log.error(e.getMessage());
            }

        }

    }

    /**
     * 刷新用户部门
     */
    @Override
    public void refreshUserDept(){
        int maxSize = 500;
        //1.通过oa_user表查询已注册用户工号和部门ID
        int userCount = oaUserService.count(new QueryWrapper<OaUser>().eq("import_status", 1));
        int step = countApart(maxSize, userCount);
        for(int i=1; i<=step; i++){
            Page<OaUser> page = new Page<>(i,maxSize);
            Page<OaUser> pageResult = oaUserMapper.selectPage(page, new QueryWrapper<OaUser>().eq("import_status", 1));
            List<OaUser> records = pageResult.getRecords();
            Map<String, List<OaUser>> collect = records.stream().filter(item->item.getPkDept()!=null).collect(Collectors.groupingBy(OaUser::getPkDept));
            log.info("分组后：{}",JSONObject.toJSONString(collect));
            //2.通过获取到的部门ID，分批进行更新，没批更新数量限制到500
            for (String dept : collect.keySet()) {
                List<String> userCodes = collect.get(dept).stream().map(OaUser::getCode).collect(Collectors.toList());
                log.info("部门：{}，工号：{}", dept, userCodes);
                String deptName = oaDeptService.getById(dept).getName();
                DataSourceContextHolder.setContextHolder("db2");
                List<Integer> turnCodes = userCodes.stream().map(Integer::valueOf).collect(Collectors.toList());
                userInfoService.update(new UpdateWrapper<UserInfo>().set("department",deptName).in("user_num",turnCodes));
                DataSourceContextHolder.clear();
            }
        }
    }

    private int countApart(int maxSize, int size){
        return (maxSize+size-1)/maxSize;
    }
}
